/*
 * CharlieplexingLed.c
 *
 *  Created on: Jan 2, 2025
 *      Author: luoxing
 */
#include "CharlieplexingLed.h"

#include "ch32v00x.h"

/*
 * IO1 GPIOC, GPIO_Pin_1
 * IO2 GPIOC, GPIO_Pin_2
 * IO3 GPIOC, GPIO_Pin_4
 * IO4 GPIOD, GPIO_Pin_4
 * IO5 GPIOD, GPIO_Pin_6
 * IO6 GPIOA, GPIO_Pin_2
 *
 * */
static CharlieplexingLed_t CharlieplexingLed[] = {
    {0,  0, GPIOC, GPIO_Pin_2, GPIOC, GPIO_Pin_1},
    {1,  0, GPIOC, GPIO_Pin_4, GPIOC, GPIO_Pin_1},
    {2,  0, GPIOD, GPIO_Pin_4, GPIOC, GPIO_Pin_1},
    {3,  0, GPIOD, GPIO_Pin_6, GPIOC, GPIO_Pin_1},
    {4,  0, GPIOA, GPIO_Pin_2, GPIOC, GPIO_Pin_1},

    {5,  0, GPIOC, GPIO_Pin_1, GPIOC, GPIO_Pin_2},
    {6,  0, GPIOC, GPIO_Pin_4, GPIOC, GPIO_Pin_2},
    {7,  0, GPIOD, GPIO_Pin_4, GPIOC, GPIO_Pin_2},
    {8,  0, GPIOD, GPIO_Pin_6, GPIOC, GPIO_Pin_2},
    {9,  0, GPIOA, GPIO_Pin_2, GPIOC, GPIO_Pin_2},

    {10, 0, GPIOC, GPIO_Pin_1, GPIOC, GPIO_Pin_4},
    {11, 0, GPIOC, GPIO_Pin_2, GPIOC, GPIO_Pin_4},
    {12, 0, GPIOD, GPIO_Pin_4, GPIOC, GPIO_Pin_4},
    {13, 0, GPIOD, GPIO_Pin_6, GPIOC, GPIO_Pin_4},
    {14, 0, GPIOA, GPIO_Pin_2, GPIOC, GPIO_Pin_4},

    {15, 0, GPIOC, GPIO_Pin_1, GPIOD, GPIO_Pin_4},
    {16, 0, GPIOC, GPIO_Pin_2, GPIOD, GPIO_Pin_4},
    {17, 0, GPIOC, GPIO_Pin_4, GPIOD, GPIO_Pin_4},
    {18, 0, GPIOD, GPIO_Pin_6, GPIOD, GPIO_Pin_4},
    {19, 0, GPIOA, GPIO_Pin_2, GPIOD, GPIO_Pin_4},

    {20, 0, GPIOC, GPIO_Pin_1, GPIOD, GPIO_Pin_6},
    {21, 0, GPIOC, GPIO_Pin_2, GPIOD, GPIO_Pin_6},
    {22, 0, GPIOC, GPIO_Pin_4, GPIOD, GPIO_Pin_6},
    {23, 0, GPIOD, GPIO_Pin_4, GPIOD, GPIO_Pin_6},
    {24, 0, GPIOA, GPIO_Pin_2, GPIOD, GPIO_Pin_6},

    {25, 0, GPIOC, GPIO_Pin_1, GPIOA, GPIO_Pin_2},
    {26, 0, GPIOC, GPIO_Pin_2, GPIOA, GPIO_Pin_2},
    {27, 0, GPIOC, GPIO_Pin_4, GPIOA, GPIO_Pin_2},
    {28, 0, GPIOD, GPIO_Pin_4, GPIOA, GPIO_Pin_2},
    {29, 0, GPIOD, GPIO_Pin_6, GPIOA, GPIO_Pin_2},
};

static const uint8_t CharlieplexingLedSize = sizeof(CharlieplexingLed) / sizeof(CharlieplexingLed[0]);
uint8_t CharlieplexingLedGetSize(void)
{
    return CharlieplexingLedSize;
}

void CharlieplexingLed_init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
}

int8_t CharlieplexingLed_write_pin(uint8_t pin, uint8_t status)
{
    if (pin >= CharlieplexingLedSize) {
        return -1;
    }
    CharlieplexingLed[pin].status = status;

    CharlieplexingLed_update(&CharlieplexingLed[pin]);

    return 0;
}

int8_t CharlieplexingLed_read_pin(uint8_t pin)
{
    if (pin >= CharlieplexingLedSize) {
        return -1;
    }
    return CharlieplexingLed[pin].status;
}

void CharlieplexingLed_update(CharlieplexingLed_t *CharlieplexingLed)
{
    GPIOA->CFGLR = 0x44444444;
    GPIOC->CFGLR = 0x44444444;
    GPIOD->CFGLR = 0x44444444;
    uint32_t high_pinpos = 0x00, low_pinpos = 0x00, pinpos = 0x00, pos = 0x00;
    uint32_t low_tmpreg = CharlieplexingLed->gpio_port_high->CFGLR, high_tmpreg = CharlieplexingLed->gpio_port_low->CFGLR;

    if (CharlieplexingLed->status == 0) {
        CharlieplexingLed->gpio_port_high->CFGLR = high_tmpreg;
        CharlieplexingLed->gpio_port_low->CFGLR = low_tmpreg;
    } else {
        for (pinpos = 0; pinpos < 0x08; pinpos++) {
            pos = ((uint32_t)0x01) << pinpos;
            if (pos == CharlieplexingLed->gpio_pin_high) {
                high_pinpos = (pinpos << 2);
            }
            if (pos == CharlieplexingLed->gpio_pin_low) {
                low_pinpos = (pinpos << 2);
            }
        }
        high_tmpreg &= ~(0xf << high_pinpos);
        low_tmpreg  &= ~(0xf << low_pinpos);
        if (CharlieplexingLed->gpio_port_high == CharlieplexingLed->gpio_port_low) {
            high_tmpreg &= low_tmpreg;
            high_tmpreg |= ((0x3 << high_pinpos)) | ((0x3 << low_pinpos));
            low_tmpreg   = high_tmpreg;
        } else {
            high_tmpreg |= (0x3 << high_pinpos);
            low_tmpreg  |= (0x3 << low_pinpos);
        }
        CharlieplexingLed->gpio_port_high->CFGLR = high_tmpreg;
        CharlieplexingLed->gpio_port_low->CFGLR = low_tmpreg;
        CharlieplexingLed->gpio_port_high->BSHR = CharlieplexingLed->gpio_pin_high;
        CharlieplexingLed->gpio_port_low->BCR = CharlieplexingLed->gpio_pin_low;
    }
}

